package NG::Chat::Client::Http;
use strict;
use warnings;

use EV;
use NG::Sys::Sock qw(
InetConnect SendMessage WaitMessage
WaitMessagePrepared PrepareWaitMessage
SendMessagePrepared PrepareSendMessage
);

our $DEBUG;

use NG::Chat::Client::Message qw(HttpRequest HttpParse);

sub Create {
	my $app = shift;
	my %http = (
		addr => [$app->{'http-connect'}{peer},$app->{'http-connect'}{port},1],
		path => $app->{'http-connect'}{path} || "",
		host => $app->{'http-connect'}{host},
		keep_alive => $app->{keep_alive},
		pool => {},
		ipool => 0,
		rid => 0,
		sid => "",
		chanel => "",
		logger => $DEBUG && $app->logger,
	);
	my $self = bless \%http,__PACKAGE__;
	
	return $self;
}
sub responser{
	my $self = shift;
	my $responser = shift;
	$self->{responser} = $responser;
}
sub cleanup {
	my $self = shift;
	delete $self->{pool};
	delete $self->{checker};
	delete $self->{keeper};
	delete $self->{responser};
	delete $self->{prepared_sender};
}
sub keepalive {
	my $self = shift;
	unless($self->{keeper}){
		$self->{keeper} = EV::timer $self->{keep_alive},$self->{keep_alive},
			sub {
				if($self->{sid}){
					send_message($self,{cmd=>"check"});
				}
			};
	}else{
		$self->{keeper}->again;
	}
}
sub send_message {
	my $self = shift;
	my $msg = shift;
	my $to_send = HttpRequest($self,$msg);
	my $sock = InetConnect(@{$self->{addr}});
	unless($sock){
		return {error=>10,text=>"connect '$@'"};
	}
	my $sender;
	unless($sender = $self->{prepared_sender}){
		$sender = $self->{prepared_sender} = PrepareSendMessage(make_getClose($self),make_getDone($self));
	}
	my $w = SendMessagePrepared($sock,$to_send,$sender);
	$self->{pool}{++$self->{ipool}} = $w;
	$w->data->[1] = $self->{ipool};
	$self->{logger}->info("in pool sender(".$msg->{cmd}.") ".$self->{ipool}." fh: ".$w->fh->fileno) if $DEBUG;
	if($msg->{cmd} eq "check"){
		#print "SEND check from: ",$sock->sockport,"\n";
		if(my $old = delete $self->{checker}){
			#print "CLOSE check from: ",$old->fh->sockport,"\n";
			$self->{logger}->info("from pool checker ".$old->data->[1]." fh: ".$old->fh->fileno) if $DEBUG;
			delete $self->{pool}{$old->data->[1]};
			#$old->fh->close;
		}
		$w->data->[2] = 1; # флаг того что это запрос чекера
		$self->keepalive;
	}
	return 0;
}
sub make_getClose {
	my $self = shift;
	return sub {
		my $w = shift;
		$self->{logger}->info("from pool close ".$w->data->[1]." fh: ".(defined $w->fh->fileno ? $w->fh->fileno : "<closed>")) if $DEBUG;
		delete $self->{pool}{$w->data->[1]};
	};
}
sub make_getMessage {
	my $self = shift;
	return sub {
		my ($w,$msg) = @_;
		#print "FROM: ",$w->fh->sockport,"\n";
		$self->{logger}->info("from pool reader ".$w->data->[1]." fh: ".$w->fh->fileno) if $DEBUG;
		delete $self->{pool}{$w->data->[1]};
		if($self->{responser}->($self,$msg)){
			send_message($self,{cmd=>"check"});
		}
	};
}
sub make_getDone {
	my $self = shift;
	my $reader = PrepareWaitMessage(\&HttpParse,make_getMessage($self),make_getClose($self));
	return sub {
		my $ow = shift;
		$self->{logger}->info("from pool sender ".$ow->data->[1]." fh: ".$ow->fh->fileno) if $DEBUG;
		delete $self->{pool}{$ow->data->[1]};
		if($DEBUG and $self->{ipool} > 100){
			EV::break EV::BREAK_ALL;
		}
		my $w = WaitMessagePrepared($ow->fh,$reader);
		$self->{pool}{++$self->{ipool}} = $w;
		$w->data->[1] = $self->{ipool};
		$self->{logger}->info("in pool reader ".$self->{ipool}." fh: ".$w->fh->fileno) if $DEBUG;
		if($ow->data->[2]){
			$self->{checker} = $w;
		}
	};
}

1;
